#include <algorithm>
#include <cstring>
#include "../utility/assert_helper.h"
#include "../utility/file_helper.h"
#include "windows_information.h"

const char	* OLD_SYSTEM_DIRECTORY = "system";
const char	* NEW_SYSTEM_DIRECTORY = "system32";
const char	* OLD_TEMP_DIRECTORY = "temp";
const char	* USERS_HOME_DIRECTORY = "Documents and Settings";
const char	* PROGRAM_FILES_DIRECTORY = "Program Files";
const char	* COMMON_USERS_DIRECTORY = "All Users";

Windows_Information::Windows_Information(const char * win_root, Windows_Edition ver) :
version_(ver)
{
	IF_NULL_RETURN(win_root);
	user_count_ = 0;
	set_windows_root_directory(win_root);
}

Windows_Information::~Windows_Information()
{
	//if (NULL != win_dir_) delete [] win_dir_;
}

int
Windows_Information::set_directories(const char * path, Path_Token token)
{
	IF_NULL_RETURN_VALUE(path, -1);

	if (SET_PATH_FROM_WINDOWS_DIR == token) {
		directories_[WINDOWS_DIR] = path;
		if ('/' == directories_[WINDOWS_DIR].at(directories_[WINDOWS_DIR].length() - 1)) {
			// 暂且不应该以 / 结尾
			return -1;
		}
		directories_[SYSTEM_DIR] += directories_[WINDOWS_DIR] + "/" +
		((version_ > WINDOWS_95 && version_ <= WINDOWS_VISTA) ? NEW_SYSTEM_DIRECTORY : OLD_SYSTEM_DIRECTORY);
		directories_[WINDOWS_TEMP] += directories_[WINDOWS_DIR] + "/" + OLD_TEMP_DIRECTORY;

		directories_[WINDOWS_ROOT] = directories_[WINDOWS_DIR].substr(0, directories_[WINDOWS_DIR].rfind("/"));
		directories_[HOME_DIR] = directories_[WINDOWS_ROOT] + "/" + USERS_HOME_DIRECTORY;
		directories_[COMMON_USER] = directories_[HOME_DIR] + "/" + COMMON_USERS_DIRECTORY;
		directories_[CURRENT_USER] = directories_[HOME_DIR] + "/" + "Administrator"; // TODO: dynamic
		directories_[PROGRAM_FILES] = directories_[WINDOWS_ROOT] + "/" + PROGRAM_FILES_DIRECTORY;
	} else {
		directories_[token] = path;
	}

	return 0;
}

const char *
Windows_Information::get_directorie(Path_Token token) const
{
	// TODO: we will check token range
	return directories_[token].c_str();
}

Windows_Edition
Windows_Information::get_windows_version() const
{
	return version_;
}

int
Windows_Information::path_expand(char * path, int size) const
{
	IF_NULL_RETURN_VALUE(path, -1);
	IF_NULL_RETURN_VALUE(size, -1);
	std::string dir = path;
	while (string_replace_first_of(dir, "\\", "/")) {/*null loop*/};

	size_t bg = dir.find_first_of("%");
	size_t ed = dir.find_last_of("%");
	if (bg < ed) {
		//printf("%s\n", dir.substr(bg, ed - bg + 1).c_str());
		std::string expand;
		std::string for_short(dir.substr(bg, ed - bg + 1));
		if (for_short == "%System%") {
			expand = get_directorie(SYSTEM_DIR);
		} else if (for_short == "%ProgramFiles%") {
			expand = get_directorie(PROGRAM_FILES);
		} else if (for_short == "%Windir%") {
			expand = get_directorie(WINDOWS_DIR);
		} else if (for_short == "%CommonUser%") {
			expand = get_directorie(COMMON_USER);
		} else if (for_short == "%CommonStartMenu%") {
			expand = std::string(get_directorie(COMMON_USER)) + "/「开始」菜单";
		} else if (for_short == "%User%") {
			expand = get_directorie(CURRENT_USER);
		} else if (for_short == "%StartMenu%") {
			expand = std::string(get_directorie(CURRENT_USER)) + "/「开始」菜单";
		} else if (for_short == "%AppData%") {
			expand = std::string(get_directorie(CURRENT_USER)) + "/Application Data";
		}

		if (!expand.empty()) {
			dir.replace(bg, ed - bg + 1, expand);
			//printf("%s\n", dir.c_str());
			if (static_cast<int>(dir.length()) <= size) {
				strncpy(path, dir.c_str(), dir.length() - 1);
				path[dir.length()] = '\0';
				return 0;
			}
			return dir.length();
		}

	} else {
		//printf("Unexpect path %s\n", dir.c_str());
		if (dir.find_first_of(":")) {
			if (!string_replace_first_of(dir, "C:/",
			std::string(get_directorie(WINDOWS_ROOT)) + "/")) {
				string_replace_first_of(dir, "c:/",
				std::string(get_directorie(WINDOWS_ROOT)) + "/");
			}
		}
		if (static_cast<int>(dir.length()) <= size) {
			strncpy(path, dir.c_str(), dir.length() - 1);
			path[dir.length()] = '\0';
			//printf("%s\n", path);
			return 0;
		}
	}
	return -1;
}

bool
Windows_Information::string_replace_first_of(std::string & content,const std::string & old_value,
const std::string & new_value)
{
   std::string::size_type   pos = content.find(old_value);
   if(pos != std::string::npos )
   {
      content.replace(pos, old_value.length(), new_value);
      return true;
   }
   return false;
}

bool
Windows_Information::string_replace_last_of(std::string & content,const std::string & old_value,
const std::string & new_value)
{
   std::string::size_type	pos = content.rfind(old_value);
   if(pos != std::string::npos )
   {
      content.replace(pos, old_value.length(), new_value);
      return true;
   }
   return false;
}

Windows_Information_Collection::Windows_Information_Collection()
{
}

Windows_Information_Collection::~Windows_Information_Collection()
{
	clear_all_information();
}

void
Windows_Information_Collection::clear_all_information()
{
	Windows_Info_Collection::iterator end = windows_info_collection_.end();
	for (Windows_Info_Collection::iterator index; end != index; ++index) {
		delete *index;
	}
	windows_info_collection_.clear();
}

int
Windows_Information_Collection::get_windows_count()const
{
	return windows_info_collection_.size();
}

int
Windows_Information_Collection::add_windows_information(const Windows_Information * win_info)
{
	IF_NULL_RETURN_VALUE(win_info, -1);
	if (!is_this_already_exist(win_info)) {
		windows_info_collection_.push_back(win_info);
		return 0;
	}
	return -1;
}

Windows_Information_Collection::Windows_Info_Collection::iterator
Windows_Information_Collection::find_windows_info_referrence(const Windows_Information * win_info)
{
	IF_NULL_RETURN_VALUE(win_info, windows_info_collection_.end());
	return
	find(windows_info_collection_.begin(), windows_info_collection_.end(), win_info);
}
int
Windows_Information_Collection::del_windows_information(const Windows_Information * win_info)
{
	IF_NULL_RETURN_VALUE(win_info, -1);
	Windows_Info_Collection::iterator iter = find_windows_info_referrence(win_info);
	if (windows_info_collection_.end() != iter) {
		delete *iter;
		windows_info_collection_.erase(iter);
		return 0;
	}
	return -1;
}

const Windows_Information *
Windows_Information_Collection::get_windows_information(size_t win_id) const
{
	if (win_id >= 0 && win_id < windows_info_collection_.size()) {
		return windows_info_collection_[win_id];
	}
	return NULL;
}

const Windows_Information *
Windows_Information_Collection::get_windows_information(const char * win_root) const
{
	IF_NULL_RETURN_VALUE(win_root, NULL);
	Windows_Info_Collection::const_iterator end = windows_info_collection_.end();
	for (Windows_Info_Collection::const_iterator index = windows_info_collection_.begin();
	end != index; ++ index) {
		if ((*index)->directories_[WINDOWS_DIR] == win_root) {
			return *index;
		}
	}
	return NULL;
}

bool
Windows_Information_Collection::is_this_already_exist(const Windows_Information * win_info) const
{
	IF_NULL_RETURN_VALUE(win_info, false);
	if (get_windows_information(win_info->get_directorie(WINDOWS_DIR))) return true;
	return false;
}
